using System.Collections.Concurrent;
using Crux.Core.Domains.Exceptions;

namespace Crux.Core.Domains;
/// <summary>
/// EventMappingsFactory
/// </summary>
public class EventMappingsFactory
    : IEventMappingsFactory
{
    #region private fields
    private readonly ConcurrentDictionary<RuntimeTypeHandle, HashSet<RuntimeTypeHandle>> mappings = new();
    #endregion  private fields


    #region implements IEventMappingsFactory
    /// <inheritdoc/>
    public IEnumerable<RuntimeTypeHandle> Get(RuntimeTypeHandle eventDateType)
    {
        if (mappings.TryGetValue(eventDateType, out var eventHandlerTypes))
        {
            return eventHandlerTypes;
        }

        throw new NoRegisterEventException($"NoRegisterEvent {Type.GetTypeFromHandle(eventDateType)?.Name}");
    }

    /// <inheritdoc/>
    public void Remove(RuntimeTypeHandle eventDataType, out IEnumerable<RuntimeTypeHandle> eventHandlerType)
    {
        if (mappings.TryRemove(eventDataType, out var result))
            eventHandlerType = result.ToList();

        else
            eventHandlerType = Enumerable.Empty<RuntimeTypeHandle>();
    }

    /// <inheritdoc/>
    public void Save(RuntimeTypeHandle eventDataType, RuntimeTypeHandle eventHandlerType)
    {
        if (mappings.TryGetValue(eventDataType, out var eventHandlerTypes))
        {
            eventHandlerTypes.Add(eventHandlerType);
        }
        else
        {
            mappings.TryAdd(eventDataType, new HashSet<RuntimeTypeHandle> { eventHandlerType });
        }
    }

    /// <inheritdoc/>
    public void Save(RuntimeTypeHandle eventDataType, IEnumerable<RuntimeTypeHandle> eventHandleTypes)
    {
        foreach (var eventHandlerType in eventHandleTypes)
        {
            Save(eventDataType, eventHandlerType);
        }
    }
    #endregion implements IEventMappingsFactory
}